/*
Long Nguyen 
UID: 005-30-140
Assignment 2: Spinwheel
*/

#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#elif defined(_WIN32)
#include <windows.h>
#include "glut.h"
//#include "lib/glut.h"
#else
#include <cstdlib>
#include <GL/glut.h>
#endif

#include <cstdio>

using namespace std;

#define XORIG 500
#define YORIG 500
#define XMAX XORIG + 240
#define YMAX YORIG + 240

int main_window = 1;
float _posX = XORIG;		// initial position of spinwheel's center
float _posY = YORIG;
int width = 1000;				// window's initial width and height
int height = 1000;
int spinwheelSize = 240;		// width and height of spinwheel
int scale=1;					// spinwheel's scale factor
float _angleRotation = 0;		// rotation angle
float _speedRotate = 0.5;		// rotation speed
float _speedTrans = 0.5;		// spinwheel's moving speed

int _blades = 4;				// number of blades


enum Direction { RIGHT, UP, LEFT, DOWN };
enum Direction _direction = RIGHT;				// moving direction while spinning

//
// Sets up clear color, shading model, etc...
//
void init(void) {

	//Clear background to black 
	glClearColor(0,0,0,0);

	// Use smooth shading.
	glShadeModel(GL_SMOOTH);
}

void idle(void)
{
	if (glutGetWindow() != main_window)
		glutSetWindow(main_window);

	// just keep redrawing the scene over and over
	glutPostRedisplay();
}

//
// While idle, spins the wheel.
//
void idleRotate(void)
{
	if (glutGetWindow() != main_window)
		glutSetWindow(main_window);

	_angleRotation += _speedRotate;
	if (_angleRotation >= 360) {
		_angleRotation -= 360;
	}

	// force to redraw
	glutPostRedisplay();
}


void keyboard(unsigned char key, int x, int y)
{
	switch(key) 
	{	
		// rotate faster		
		case 'f':
		case 'F':
			_speedRotate += 0.1;
			if (_speedRotate > 2) {
				_speedRotate = 2;
			}
			break;
		
		// rotate slower
		case 's':
		case 'S':
			_speedRotate -= 0.1;
			if (_speedRotate < 0) {
				_speedRotate = 0;
			}
			break;

		// quit
		case 27:		// esc
		case 'q':
		case 'Q':
			exit(0);
			break;
		case 50:		// '2'
			_blades = 2;
			break;
		case 51:		// '3'
			_blades = 3;
			break;
		case 52:		// '4'
			_blades = 4;
			break;
		case 53:		// '5'
			_blades = 5;
			break;
		case 54:		// '6'
			_blades = 6;
			break;

		//case 43:		// + (plus)
		//	_blades++;
		//	if (_blades > 6) {
		//		_blades = 6;
		//	}
		//	break;

		//case 45:		// - (minus)
		//	_blades--;
		//	if (_blades < 2) {
		//		_blades = 2;
		//	}
		//	break;
    }

    glutPostRedisplay();
}

// the window has changed shapes, fix ourselves up
void reshape(int x, int y)
{
	width = x;
	height = y;
	printf("%d %d\n", x,y);
	glViewport(0,0,width,height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,width,0,height,-100,10000);
	glMatrixMode(GL_MODELVIEW);
    glutPostRedisplay();
}

//
// Translate spinwheel in left, right, up, down directions.
//
void moveSpinwheel() {
	
	switch (_direction) {
		// spinwheel moves RIGHT
		case RIGHT:
			if (_posX + _speedTrans <= XMAX) {
				_posX += _speedTrans;
				glTranslatef(_speedTrans, 0, 0.0);
			}
			else {
				glTranslatef(XMAX - _posX, 0, 0.0);				
				_posX = XMAX;
				_direction = UP;
			}
			break;
		// spinwheel moves UP
		case UP:
			if (_posY + _speedTrans <= YMAX) {
				_posY += _speedTrans;
				glTranslatef(0, _speedTrans, 0.0);
			}
			else {
				glTranslatef(0, YMAX - _posY, 0.0);
				_posY = YMAX;
				_direction = LEFT;
			}
			break;
		// spinwheel moves LEFT
		case LEFT:
			if (_posX - _speedTrans >= XORIG) {
				_posX -= _speedTrans;
				glTranslatef(-_speedTrans, 0, 0.0);
			}
			else {
				glTranslatef(_posX - XORIG, 0, 0.0);				
				_posX = XORIG;
				_direction = DOWN;
			}
			break;
		// spinwheel moves DOWN
		case DOWN:
			if (_posY - _speedTrans >= YORIG) {
				_posY -= _speedTrans;
				glTranslatef(0, -_speedTrans, 0.0);
			}
			else {
				glTranslatef(_posY - YORIG, 0, 0.0);				
				_posY = YORIG;
				_direction = RIGHT;
			}
			break;
	}
}

//
// Rotate spinwheel
//
void rotateSpinwheel(float posX, float posY, float angle) {
	
	// translate back to where it was
	glTranslatef(posX, posY, 0.0);
	// rotate about origin/ z-axis
    glRotatef(angle, 0.0, 0.0, 1.0);
	// translate to origin
	glTranslatef(-posX, -posY, 0.0);
}

//
// Draws a spin wheel with 4 blades.
//
void drawBlades() {

	glBegin(GL_TRIANGLES);	
	{					
		// draw left spinwheel blade
		glColor3f(1, 0, 0);	
		glVertex3f(_posX, _posY, 0);
		glVertex3f(_posX - (spinwheelSize/2)/scale, _posY + (spinwheelSize/6)/scale, 0);
		glVertex3f(_posX - (spinwheelSize/2)/scale, _posY - (spinwheelSize/6)/scale, 0);

		// draw right spinwheel blade
		glColor3f(0, 1, 0);	
		glVertex3f(_posX, _posY, 0);
		glVertex3f(_posX + (spinwheelSize/2)/scale, _posY + (spinwheelSize/6)/scale, 0);
		glVertex3f(_posX + (spinwheelSize/2)/scale, _posY - (spinwheelSize/6)/scale, 0);

		// draw top spinwheel blade
		glColor3f(0, 0, 1);	
		glVertex3f(_posX, _posY, 0);
		glVertex3f(_posX + (spinwheelSize/6)/scale, _posY + (spinwheelSize/2)/scale, 0);
		glVertex3f(_posX - (spinwheelSize/6)/scale, _posY + (spinwheelSize/2)/scale, 0);

		// draw bottom spinwheel blade
		glColor3f(1, 1, 0);
		glVertex3f(_posX, _posY, 0);
		glVertex3f(_posX + (spinwheelSize/6)/scale, _posY - (spinwheelSize/2)/scale, 0);
		glVertex3f(_posX - (spinwheelSize/6)/scale, _posY - (spinwheelSize/2)/scale, 0);
	}
	glEnd();
}


//
// Draws 1 single blade, angle determines direction of the blade.
//
void drawBlade(float angle, float r, float g, float b) {

	glPushMatrix();		
	rotateSpinwheel( _posX, _posY, angle);

	glBegin(GL_TRIANGLES);	
	{		
		glColor3f(r, 0, 0);
		glVertex3f(_posX, _posY, 0);
		glColor3f(0, g, 0);
		glVertex3f(_posX - (spinwheelSize/2)/scale, _posY + (spinwheelSize/6)/scale, 0);
		glColor3f(0, 0, b);
		glVertex3f(_posX - (spinwheelSize/2)/scale, _posY - (spinwheelSize/6)/scale, 0);						
	}
	glEnd();

	glPopMatrix();
}

void drawBlades2() {

	switch (_blades) {
		case 2:
			drawBlade(-180, 1, 0, 0);
			drawBlade(0, 0, 1, 0);	
			break;
		case 3:
			drawBlade(-120, 1, 0, 0);
			drawBlade(120, 0, 1, 0);
			drawBlade(0, 0, 0, 1);
			break;
		case 4:
			drawBlade(-90, 1, 0, 0);			
			drawBlade(90, 0, 1, 0);
			drawBlade(180, 1, 1, 0);
			drawBlade(0, 0, 0, 1);
			break;
		case 5:
			drawBlade(-72, 1, 0, 0);			
			drawBlade(-144, 0, 1, 0);
			drawBlade(72, 1, 1, 0);
			drawBlade(144, 0, 0, 1);
			drawBlade(0, 0, 1, 1);
			break;
		case 6:
			drawBlade(-60, 1, 0, 0);			
			drawBlade(-120, 0, 1, 0);
			drawBlade(60, 1, 1, 0);
			drawBlade(120, 0, 0, 1);
			drawBlade(180, 0, 1, 1);
			drawBlade(0, 1, 0, 1);
			break;

	}	
}


void display( )
{
	
	glMatrixMode(GL_MODELVIEW);
	
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);        
	glLoadIdentity();

	// Translate spinwheel in left, right, up, down directions.
	moveSpinwheel();

	// save matrix for translating spinwheel later
	//glPushMatrix();
		
	// Rotate spinwheel
	rotateSpinwheel(_posX, _posY, _angleRotation);

	// Draws a spin wheel with 4 blades.
    //drawBlades();

	drawBlades2();

	//glPopMatrix();

	glutSwapBuffers();
}

int main(int argc,	char* argv[])
{
	//
	// create the glut window
	//
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
	glutInitWindowSize(width, height);
	glutInitWindowPosition(100,100);
	main_window = glutCreateWindow("Assignment 2 - Spin wheel");
    glPointSize(1);

	init();

	glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutReshapeFunc(reshape);
    //glutIdleFunc(idle);

	// make it spin continuously
	glutIdleFunc(idleRotate);

	glMatrixMode(GL_PROJECTION);
    glOrtho(0,width,0,height,-100,10000);
	glMatrixMode(GL_MODELVIEW);
	// give control over to glut
	glutMainLoop();
	
	return 0;
}
